using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using Raona.Code.Contracts.EventArguments;
using Raona.Code.Model;

namespace Raona.Code.AssemblyInspection
{
    public abstract class AssemblyOperationContractInspectorBase : MarshalByRefObject
    {
        /// <summary>
        /// The assembly to inspect
        /// </summary>
        protected string contractsAssemblyPath = null;

        protected ConcurrentDictionary<string, Namespace> namespaces = null;

        /// <summary>
        /// Event fired on completion of every step in the inspection process
        /// </summary>
        public virtual event EventHandler<ProgressEventArgs> ProgressChanged;

        /// <summary>
        /// Event fired when the inspection process finishes
        /// </summary>
        public virtual event EventHandler<ProgressResultEventArgs> ProcessFinished;

        /// <summary>
        /// The collection of namespaces resulting of the inspection process
        /// </summary>
        public IEnumerable<Namespace> Namespaces
        {
            get
            {
                return this.namespaces.Values.AsEnumerable();
            }
        }

        protected string GetOverloadedName(MethodInfo methodInfo)
        {
            OperationContractAttribute attribute = methodInfo.GetCustomAttributes(typeof(OperationContractAttribute), false)[0] as OperationContractAttribute;
            return string.IsNullOrEmpty(attribute.Name) ? methodInfo.Name : attribute.Name;
        }

        protected string GetTypeName(Type type)
        {
            string typeName = null;
            if (type.IsGenericType)
            {
                int argumentCount = type.GetGenericArguments().Length;
                typeName = type.ToString().Replace(string.Format("`{0}[", argumentCount), "<").Replace("]", ">");
            }
            else
            {
                typeName =
                    type == typeof(void) ? 
                                "void" :
                                type.IsEnum && type.IsNested ? 
                                    type.FullName.Replace("+", ".") :
                                    type.FullName;
            }
            return typeName;
        }

        protected void ReportProgress(Interface itf)
        {
            if (this.ProgressChanged != null)
            {
                this.ProgressChanged(this, new ProgressEventArgs { Message = string.Format("Processing interface: {0}", itf.Name) });
            }
        }

        protected void ReportResult()
        {
            Dictionary<string, Namespace> result = new Dictionary<string, Namespace>();
            foreach (KeyValuePair<string, Namespace> item in this.namespaces)
            {
                result.Add(item.Key, item.Value);
            }
            this.ReportResult(new ProgressResultEventArgs(result));
        }

        protected void ReportResult(Exception error)
        {
            this.ReportResult(new ProgressResultEventArgs(error));
        }

        private void ReportResult(ProgressResultEventArgs resultEventArgs)
        {
            if (this.ProcessFinished != null)
            {
                this.ProcessFinished(this, resultEventArgs);
            }
        }
    }
}